/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-04-27     Administrator       the first version
 */
#include <CONTROL/control.h>
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include <easyflash.h>

#define DBG_ENABLE
#define DBG_SECTION_NAME "control"
#define DBG_LEVEL DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>

#include "MQTT/mqtt.h"
#include "GLOBAL/code.h"

/**
 * 该函数初始化检测控制引脚.
 * 
 * @return 
 */
void ctl_pin_init() 
{
    // 引脚初始化
    rt_pin_mode(PIN_IN_0, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(PIN_IN_1, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(PIN_IN_2, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(PIN_IN_3, PIN_MODE_INPUT_PULLUP);

    rt_pin_mode(PIN_OUT_0, PIN_MODE_OUTPUT);
    rt_pin_mode(PIN_OUT_1, PIN_MODE_OUTPUT);
    rt_pin_mode(PIN_OUT_2, PIN_MODE_OUTPUT);
    rt_pin_mode(PIN_OUT_3, PIN_MODE_OUTPUT);

    // pin in
    for (int i = 0; i < (int)(PIN_NUM / 2); i++)
    {
        ctl_pins[i].status = 0;
        ctl_pins[i].mode = PIN_MODE_INPUT_PULLUP;
    }
    ctl_pins[0].pin = PIN_IN_0;
    ctl_pins[1].pin = PIN_IN_1;
    ctl_pins[2].pin = PIN_IN_2;
    ctl_pins[3].pin = PIN_IN_3;

    // pin out
    for (int i = 5; i < (int)(PIN_NUM / 2); i++)
    {
        ctl_pins[i].status = 0;
        ctl_pins[i].mode = PIN_MODE_OUTPUT;
    }
    ctl_pins[4].pin = PIN_OUT_0;
    ctl_pins[5].pin = PIN_OUT_1;
    ctl_pins[6].pin = PIN_OUT_2;
    ctl_pins[7].pin = PIN_OUT_3;
    
    // 读取auto配置
    // ef_get_env_blob("autos", &autos, sizeof(autos), 0);
    int read_len = ef_get_env_blob("autos", &autos, sizeof(autos), 0);
    if(read_len == 0) {
        LOG_W("auto arr not config !!!");
    } 
    ctl_auto_print();
}

/**
 * 该函数表格形式打印auto自动执行的任务信息.
 * 
 * @return 
 */
void ctl_auto_print() {
    LOG_D("");
    LOG_D("============= Auto Run Table ===================");
    LOG_D("| id\t| logic\t| conditions\t| runs\t\t|");
    LOG_D("------------------------------------------------");
    for (int i = 0; i < AUTO_NUM; i++) 
    {
        if(autos[i].enable == 1) {
            LOG_D("| %d\t| %d\t|\\\t\t|\\\t\t|", i, autos[i].logic);
            for (int j = 0; j < AUTO_CONDITION_NUM; j++) 
            {
                if (autos[i].condition[j].enable == 1 && autos[i].run[j].enable == 1)
                {
                    LOG_D("|\t|\t|pin:%d,status:%d\t|pin:%d,status:%d\t|",
                        autos[i].condition[j].pin_id,
                        autos[i].condition[j].status,
                        autos[i].run[j].pin_id,
                        autos[i].run[j].status);
                }
                else if (autos[i].condition[j].enable == 1)
                {
                    LOG_D("|\t|\t|pin:%d,status:%d\t|\t\t|",
                        autos[i].condition[j].pin_id,
                        autos[i].condition[j].status);
                }
                else if (autos[i].run[j].enable == 1)
                {
                    LOG_D("|\t|\t|\t\t|pin:%d,status:%d\t|",
                        autos[i].run[j].pin_id,
                        autos[i].run[j].status);
                }
            }
            LOG_D("------------------------------------------------");
        }
    }
    LOG_D("| [pin]: range 0~8;\t\t\t\t|");
    LOG_D("| [logic]: 1 -> AND, 2 -> OR;\t\t\t|");
    LOG_D("| [status]: 0->low level, 1->high level;\t|");
    LOG_D("================================================");
}

/**
 * 该函数更新自动化执行任务.
 * 
 * @param msg : json 格式更新单个任务, Example: {"id":0,"enable":1,"logic":1,"conditions":[],"runs":[]}
 * 
 * @return 
 */
void clt_auto_update(cJSON *msg)
{
    // 解析json内容
    cJSON *id = cJSON_GetObjectItem(msg, "id");
    cJSON *enable = cJSON_GetObjectItem(msg, "enable");
    cJSON *logic = cJSON_GetObjectItem(msg, "logic");
    cJSON *condition = cJSON_GetObjectItem(msg, "conditions");
    cJSON *run = cJSON_GetObjectItem(msg, "runs");

    int i = id->valueint;
    autos[i].logic = logic->valueint;
    autos[i].enable = enable->valueint;

    // 清除个引脚enable
    for (int j = 0; j < 5; j++) //遍历最外层json键值对
    {
        autos[i].condition[j].enable = 0;
        autos[i].run[j].enable = 0;
    }

    for (int c = 0; c < cJSON_GetArraySize(condition); c++) //遍历最外层json键值对
    {
        cJSON *item = cJSON_GetArrayItem(condition, c);
        cJSON *pin = cJSON_GetObjectItem(item, "pin");
        cJSON *status = cJSON_GetObjectItem(item, "status");
        autos[i].condition[c].pin_id = pin->valueint;
        autos[i].condition[c].status = status->valueint;
        autos[i].condition[c].enable = 1;
    }
    for (int r = 0; r < cJSON_GetArraySize(run); r++) //遍历最外层json键值对
    {
        cJSON *item = cJSON_GetArrayItem(run, r);
        cJSON *pin = cJSON_GetObjectItem(item, "pin");
        cJSON *status = cJSON_GetObjectItem(item, "status");
        autos[i].run[r].pin_id = pin->valueint;
        autos[i].run[r].status = status->valueint;
        autos[i].run[r].enable = 1;
    }
    ctl_auto_print();
    int result = ef_set_env_blob("autos", &autos, sizeof(autos));
    LOG_D("ef write [autos] result: %d", result);
}

/**
 * 该函数检测自动化任务, 满足条件执行.
 * 
 * @return 
 */
void ctl_auto_check()
{
    for (int i = 0; i < AUTO_NUM; i++) //遍历最外层json键值对
    {
        int is_run = 0;
        if (autos[i].enable != 1)
        {
            continue;
        }
        for (int c = 0; c < AUTO_CONDITION_NUM; c++)
        {
            if (autos[i].condition[c].enable != 1)
            {
                continue;
            }
            int condition_pin_id = autos[i].condition[c].pin_id;
            int condition_status = autos[i].condition[c].status;
            // 根据condition中的pin_id, 获取引脚状态
            int pin_status = ctl_pins[condition_pin_id].status;
            if (autos[i].logic == AUTO_LOGIC_AND) // and
            {
                is_run = 1;
                if (condition_status != pin_status) 
                {
                    is_run = 0;
                    break;
                }
            }
            if (autos[i].logic == AUTO_LOGIC_OR) // or
            {
                if (condition_status == pin_status)
                {
                    is_run = 1;
                    break;
                }
            }
        }
        if (is_run)
        {
            LOG_D("");
            LOG_D("========= Auto Run Once=========");
            LOG_D("| auto_id\t| auto_logic\t|");
            LOG_D("--------------------------------");
            LOG_D("| %d\t\t| %d\t\t|", i, autos[i].logic);
            LOG_D("================================");
            for (int r = 0; r < AUTO_RUN_NUM; r++) //遍历最外层json键值对
            {
                if (autos[i].run[r].enable == 1)
                {
                    // 执行
                    int run_pin_id = autos[i].run[r].pin_id;
                    int run_status = autos[i].run[r].status;
                    // 根据run中的pin_id, 获取引脚
                    long run_pin = ctl_pins[run_pin_id].pin;
                    rt_pin_write(run_pin, run_status);
                    // 更新引脚状态
                    ctl_pins[run_pin_id].status = run_status;
                }
            }
        }
    }
}

/**
 * 该函数表格形式打印引脚状态.
 * Example:
 * ================ Pin Status Table ==============
 * | pin_id      | status        | mode            |
 * ------------------------------------------------
 * | 0           | 1             | 2               |
 * | 1           | 0             | 2               |
 * ------------------------------------------------
 * @return 
 */
void ctl_pin_print() {
    LOG_D("");
    LOG_D("================ Pin Status Table ==============");
    LOG_D("| pin_id\t| status\t| mode\t\t|");
    LOG_D("------------------------------------------------");
    for (int i = 0; i < PIN_NUM; i++) //遍历最外层json键值对
    {
        LOG_D("| %d\t\t| %d\t\t| %d\t\t|", i, ctl_pins[i].status, ctl_pins[i].mode);
    }
    LOG_D("================================================");
}

/**
 * This function get pin status, use hex format, low to high bit.
 * Pin Status Example:
 * 0x0b -> 00001011 : pin[0] -> 1, pin[1] -> 1, pin[2] -> 0 ...
 *
 * @return pin status
 */
int ctl_pin_get() {
    int status = 0;
    for (int i = 0; i < PIN_NUM; i++) //遍历最外层json键值对
    {
        status += (0xff & ctl_pins[i].status) << i;
    }
    return status;
}

/**
 * 该函数上传引脚信息至mqtt服务器.
 *
 * @return 
 */
void ctl_pin_upload(){
    int status = ctl_pin_get();
    char buf[50];
    snprintf(buf, sizeof(buf), "{\"aswcode\":\"%d\",\"aswmsg\":%d}", CODE_GET_PIN, status);
    mqtt_publish(buf);
}

/**
 * 该函数检测引脚状态，上传引脚状态至mqtt服务器.
 *
 * @return 
 */
void ctl_pin_check()
{
    int is_send = 0;
    for (int i = 0; i < PIN_NUM; i++) //遍历最外层json键值对
    {
        // 输入引脚判断
        if (ctl_pins[i].mode == PIN_MODE_INPUT_PULLUP) {
            int value = rt_pin_read(ctl_pins[i].pin);
            if (value != ctl_pins[i].status) {
                ctl_pins[i].status = value;
                LOG_D("Pin Changed -> pin: %d, status: %d", i, value);
                is_send = 1;
                // 每次引脚变化时，检测自动执行任务
                ctl_auto_check();
            }
        }
    }
    if (is_send == 1){
        ctl_pin_upload();
    }
}


// 自动初始化
// INIT_APP_EXPORT(ctl_pin_init);

#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT(ctl_auto_print, print auto info);
MSH_CMD_EXPORT(ctl_pin_print, print pin current info);
#endif /* FINSH_USING_MSH */
